package com.shanjupay.transaction.service;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shanjupay.common.cache.Cache;
import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.util.RedisUtil;
import com.shanjupay.transaction.api.PayChannelService;
import com.shanjupay.transaction.api.dto.PayChannelDTO;
import com.shanjupay.transaction.api.dto.PayChannelParamDTO;
import com.shanjupay.transaction.api.dto.PlatformChannelDTO;
import com.shanjupay.transaction.convert.PayChannelParamConvert;
import com.shanjupay.transaction.convert.PlatformChannelConvert;
import com.shanjupay.transaction.entity.AppPlatformChannel;
import com.shanjupay.transaction.entity.PayChannelParam;
import com.shanjupay.transaction.entity.PlatformChannel;
import com.shanjupay.transaction.mapper.AppPlatformChannelMapper;
import com.shanjupay.transaction.mapper.PayChannelParamMapper;
import com.shanjupay.transaction.mapper.PlatformChannelMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class PayChannelServiceImpl implements PayChannelService {
    /*
    * 获取平台的服务类型
    *
    * */
    //1注入支付服务平台的Mapper接口
    @Autowired
    PlatformChannelMapper platformChannelMapper;
    //注入服务与应用的mapper
    @Autowired
    AppPlatformChannelMapper appPlatformChannelMapper;

    @Autowired
    PayChannelParamMapper payChannelParamMapper;

    //注入Cache抽象接口 实现类RedisCache 使用该RedisCache操作redis实现缓存
    //添加支付渠道参数到数据库时，同时把支付渠道参数添加redis缓存中,
    //查询时，先从Redis中进行查询支付渠道参数，没有查询到，从数据库及进行查询，同时把查询到数据添加到redis缓存中
    @Autowired
    Cache cache;
    @Override
    public List<PlatformChannelDTO> queryPlatformChannel() throws BusinessException {
        //使用注入的平台服务mapper接口调用selectList(条件)根据条件进行查询，条件为null
        //表示查询所有的服务类型
        List<PlatformChannel> platformChannels = platformChannelMapper.selectList(null);
        //使用对象转化接口进行对象进行转化
       return PlatformChannelConvert.INSTANCE.listentity2listdto(platformChannels);

    }


    /*
     * 为某个应用进行绑定服务
     * 实质：应用于服务关联表进行插入数据，实现服务与应用的绑定
     *
     * */
    @Override
    @Transactional
    public void bindPlatformChannelForApp(String appId, String platformChannelCodes) throws BusinessException {
        //实现步骤 1在app_platform_channel表中进行查询是否存在该记录
        //如果存在该应用已经进行绑定服务，否则进行app_platform_channel表插入进行服务的绑定
        //查询根据appId和platformChannelCodes服务码进行查询app_platform_channel服务与应用关联表中的记录
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>().eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannelCodes));
        if (appPlatformChannel == null){
            //该应用于该服务没有进行绑定的 插入记录进行应用与服务进行绑定
            //创建服务与应用关联记录的实体
            AppPlatformChannel entity = new AppPlatformChannel();
            //设置appId和服务码
            entity.setAppId(appId);
            entity.setPlatformChannel(platformChannelCodes);
            appPlatformChannelMapper.insert(entity);
        }
    }

    /*
    * 查询应用是否已经绑定服务
    * 1表示该服务已经进行绑定
    * 0表示该服务未与该应用进行绑定
    * */
    @Override
    public int queryAppBindPlatformChannel(String appId, String platformChannel) throws BusinessException {
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId, appId)
                .eq(AppPlatformChannel::getPlatformChannel, platformChannel));
        if(appPlatformChannel != null){
            return 1;
        }else{
            return 0;
        }
    }

    /*
    *
    * 根据服务类型查询支付渠道列表
    * */
    @Override
    public List<PayChannelDTO> queryPayChannelByPlatformChannel(String platformChannelCode) throws BusinessException {
        return platformChannelMapper.selectPayChannelByPlatformChannel(platformChannelCode);
    }

    /*
    * 配置支付渠道参数
    *
    * */
    @Override
    public void savePayChannelParam(PayChannelParamDTO payChannelParamDTO) throws BusinessException{

        //1参数校验  支付渠道dao实体 appId 服务类型码 支付渠道的非空校验
        if(payChannelParamDTO == null || StringUtils.isBlank(payChannelParamDTO.getAppId())  || StringUtils.isBlank(payChannelParamDTO.getPlatformChannelCode()) || StringUtils.isBlank(payChannelParamDTO.getPayChannel())){
            throw  new BusinessException(CommonErrorCode.E_300009);
        }

        //获取应用与服务关联表中应用于服务类型绑定的Id
        Long id = selectIdByAppPlatformChannel(payChannelParamDTO.getAppId(), payChannelParamDTO.getPlatformChannelCode());
        //进行判断获取应用于服务类型绑定id空校验 抛出应用于服务类型没有进行绑定异常
        if(id == null){
            throw new BusinessException(CommonErrorCode.E_300010);
        }

        //根据应用于服务类型绑定id与服务渠道进行查询pay_channel_param表中的支付渠道参数实体
        PayChannelParam payChannelParam = payChannelParamMapper.selectOne(new LambdaQueryWrapper<PayChannelParam>()
                .eq(PayChannelParam::getAppPlatformChannelId, id).eq(PayChannelParam::getPayChannel, payChannelParamDTO.getPayChannel()));

        if(payChannelParam != null){
            //更新支付渠道参数
            payChannelParam.setChannelName(payChannelParamDTO.getChannelName());
            payChannelParam.setParam(payChannelParamDTO.getParam());
            //使用支付渠道mapper接口调用updateById(entity)根据主键进行更新
            payChannelParamMapper.updateById(payChannelParam);
        }else{
            //新增支付渠道参数 新增支付渠道参数实体  dto属性复制entity
            PayChannelParam entity = PayChannelParamConvert.INSTANCE.dto2entity(payChannelParamDTO);
            //新增·支付渠道参数实体，做一下设置参数 如id新增成功后mp自动帮我们生成的，id设置为空，一旦新增成功，自动雪花算法生成Long类型的
            entity.setId(null);
            //服务类型与应用绑定的id设置
            entity.setAppPlatformChannelId(id);
            payChannelParamMapper.insert(entity);
        }
        //添加支付渠道参数时，把数据添加到redis缓存中
        updateCache(payChannelParamDTO.getAppId(),payChannelParamDTO.getPlatformChannelCode());
    }

    /*
    * 根据应用appId 和服务类型获取支付渠道列表
    *
    * */
    @Override
    public List<PayChannelParamDTO> queryPayChannelParamByAppAndPlatform(String appId, String platformChannel) throws BusinessException {
        //先从redis中进行查询支付渠道参数列表
        //1先构造key
        String redisKey = RedisUtil.keyBuilder(appId,platformChannel);
        //判断该key是否存在在redis中 如果redis中存在该key就进行获取对应的支付渠道参数列表的json字符串并进行解析需要支付参数列表
        Boolean exists = cache.exists(redisKey);
        if(exists){
          return  JSON.parseArray(cache.get(redisKey), PayChannelParamDTO.class);
        }
        //如果redis查询不到，从数据库进行查询，并且把查询到支付渠道参数列表添加的redis
        //1根据appId 和 服务类型 获取应用与服务类型绑定的id,
        Long id = selectIdByAppPlatformChannel(appId, platformChannel);




        //使用应用与服务的绑定id进行测试 条件查询条件写错了，写成id 应该写成服务于应用绑定的id：即AppPlatformChannelId
        List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, id));
        //且把查询到支付渠道参数列表添加的redis
        updateCache(appId,platformChannel);
        return PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);
    }

    /*
    *
    * 根据应用appId 和 服务类型 和支付渠道 获取对应的支付渠道参数
    *
    *
    * */
    @Override
    public PayChannelParamDTO queryParamByAppPlatformAndPayChannel(String appId, String platformChannel, String payChannel) throws BusinessException {
        //获取应用于服务类型绑定id
        List<PayChannelParamDTO> payChannelParamDTOS = queryPayChannelParamByAppAndPlatform(appId, platformChannel);

        //直接遍历获取支付渠道参数列表，加个判断 找到支付渠道对应支付渠道参数 就可以了·
        for (PayChannelParamDTO payChannelParamDTO:payChannelParamDTOS) {
            if(payChannelParamDTO.getPayChannel().equals(payChannel)){
                return payChannelParamDTO;
            }
        }
        return null;
    }

    //根据appId和服务类型进行查询app_platform_channel的应用与服务类型绑定的id  selectIdByAppPlatformChannel
    private Long selectIdByAppPlatformChannel(String appId,String platformChannelCode){
        //使用appPlatformChannelMapper查询单条 应用与服务类型关联表中记录，从关联表中进行获取到该记录里面的应用与服务类型关联表的Id
        AppPlatformChannel appPlatformChannel = appPlatformChannelMapper.selectOne(new LambdaQueryWrapper<AppPlatformChannel>()
                .eq(AppPlatformChannel::getAppId,appId)
                .eq(AppPlatformChannel::getPlatformChannel,platformChannelCode));
        //从关联表中进行获取到应用于服务类型绑定id
        if(appPlatformChannel != null){
            return appPlatformChannel.getId();
        }
       return null;
    }
    //将支付渠道参数更新缓存到redis数据库中
    private void updateCache(String appId,String platformChannelCode){
        //构造一个key(支付渠道参数列表的key) 使用RedisUtil工具类的keyBuild方法进行构造
        //这种结构的key 前缀:appId:platformChannelCode  SJ_PAY_PARAM:dc085e83-689b-4842-bbde-e67f4e58d8b9:shanju_c2b
        String redisKey = RedisUtil.keyBuilder(appId,platformChannelCode);
        //判断redis获取数据库的是否存在上面构造key
        Boolean exists = cache.exists(redisKey);
        if(exists){
            //如果该key存在 删除redis中key，
            cache.del(redisKey);
        }
        //使用上面构造的key
        //1在数据库根据应用id和服务类型code获取支付渠道参数列表
       //根据appId和服务类型进行查询服务类型于应用的绑定id
        Long id = selectIdByAppPlatformChannel(appId, platformChannelCode);
        if(id != null){
            //进行查询服务渠道列表
            List<PayChannelParam> payChannelParams = payChannelParamMapper.selectList(new LambdaQueryWrapper<PayChannelParam>().eq(PayChannelParam::getAppPlatformChannelId, id));
            List<PayChannelParamDTO> payChannelParamDTOS = PayChannelParamConvert.INSTANCE.listentity2listdto(payChannelParams);
            //存入redis
            cache.set(redisKey,JSON.toJSON(payChannelParamDTOS).toString());
        }
    }

}
